package com.carb.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.carb.constant.MessageConstant;
import com.carb.constant.PasswordConstant;
import com.carb.dto.EmployeeAddDTO;
import com.carb.dto.EmployeePageQueryDTO;
import com.carb.dto.EmployeeUpdateDTO;
import com.carb.entity.Employee;
import com.carb.entity.User;
import com.carb.enums.*;
import com.carb.exception.AccountNotFoundException;
import com.carb.mapper.EmployeeMapper;
import com.carb.mapper.UserMapper;
import com.carb.query.PageQueryUtils;
import com.carb.result.PageResult;
import com.carb.service.IEmployeeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carb.utils.RegexUtils;
import com.carb.vo.EmployeeVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 员工管理 服务实现类
 * </p>
 *
 * @author XuChaoyang
 * @since 2025-01-18
 */
@Service
@Slf4j
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {

    @Resource
    private UserMapper userMapper;

    /**
     * 新增员工
     * @param employeeAddDTO 新增员工信息
     */
    @Override
    @Transactional
    public void addEmployee(EmployeeAddDTO employeeAddDTO) {
        // 1、正则校验
        // 移动电话
        RegexUtils.checkMobilePhone(employeeAddDTO.getMobilePhone());
        // 身份证号码
        RegexUtils.checkIdNumber(employeeAddDTO.getIdNumber());
        // 电子邮箱
        RegexUtils.checkEmail(employeeAddDTO.getEmail());

        // 2、检查用户和员工是否已经存在且逻辑删除（已删除）
        User isUserExist = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, employeeAddDTO.getUsername())
                .eq(User::getDeleted, CommonDeleted.DELETED));
        if (isUserExist != null) {
            // 用户id
            Long userId = isUserExist.getId();
            // 更新用户逻辑删除为未删除
            BeanUtils.copyProperties(employeeAddDTO, isUserExist);
            isUserExist.setDeleted(CommonDeleted.NOT_DELETED)
                    .setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()))
                    .setCreateTime(LocalDateTime.now())
                    .setUpdateTime(LocalDateTime.now())
                    .setLastLoginTime(null);
            userMapper.update(isUserExist, Wrappers.lambdaUpdate(User.class)
                    .eq(User::getId, userId));
            // 更新员工逻辑删除为未删除
            Employee isEmployeeExist = this.getOne(Wrappers.lambdaQuery(Employee.class)
                    .eq(Employee::getUserId, userId)
                    .eq(Employee::getDeleted, CommonDeleted.DELETED));
            if (isEmployeeExist != null) {
                BeanUtils.copyProperties(employeeAddDTO, isEmployeeExist);
                isEmployeeExist.setDeleted(CommonDeleted.NOT_DELETED)
                        .setCreateTime(LocalDateTime.now())
                        .setUpdateTime(LocalDateTime.now());
                this.update(isEmployeeExist, Wrappers.lambdaUpdate(Employee.class)
                        .eq(Employee::getUserId, userId));
            }
            // 跳过新增逻辑
            return;
        }

        // 3、用户属性拷贝
        User user = new User();
        BeanUtils.copyProperties(employeeAddDTO, user);

        // 4、填充用户属性
        // 4.1、设置默认密码123456（MD5加密）
        user.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
        // 4.2、设置用户状态，默认为启用状态
        user.setStatus(CommonStatus.ENABLED);
        // 4.3、设置用户角色，当前为员工
        user.setRole(UserRole.EMPLOYEE);

        // 5、新增用户（insert后主键会自动set到实体的id字段，只需要getId()就好）
        userMapper.insert(user);

        // 6、员工属性拷贝
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeAddDTO, employee);
        // 6.1、设置用户id
        employee.setUserId(user.getId());

        // 7、新增员工
        this.save(employee);
    }

    /**
     * 员工分页查询
     * @param employeePageQueryDTO 查询条件
     * @return 员工分页查询结果
     */
    @Override
    public PageResult<EmployeeVO> pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
        // 1、获取查询属性
        // 1.1、分页属性
        Long pageNum = PageQueryUtils.checkPageNum(employeePageQueryDTO.getPageNum());
        Long pageSize = PageQueryUtils.checkPageSize(employeePageQueryDTO.getPageSize());
        String orderBy = employeePageQueryDTO.getOrderBy();
        Boolean isAsc = employeePageQueryDTO.getIsAsc();
        // 1.2、查询属性
        String name = employeePageQueryDTO.getName();
        CommonStatus status = employeePageQueryDTO.getStatus();
        EmployeePosition position = employeePageQueryDTO.getPosition();

        // 2、构建条件
        // 2.1、分页条件
        Page<Employee> page = Page.of(pageNum, pageSize);
        // 2.2、排序条件
        PageQueryUtils.applySorting(page, orderBy, isAsc);
        // 2.3、空结果
        PageResult<EmployeeVO> emptyPageResult = new PageResult<>(page.getTotal(), page.getPages(), Collections.emptyList());

        // 3、用户表查询（员工姓名（非空）、角色=员工、逻辑删除（未删除））
        List<User> userList = userMapper.selectList(Wrappers.lambdaQuery(User.class)
                .like(name != null, User::getName, name)
                .eq(status != null, User::getStatus, status)
                .eq(User::getRole, UserRole.EMPLOYEE)
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));
        if (userList.isEmpty()) return emptyPageResult;

        // 4、构造用户id与用户对象的映射关系
        Map<Long, User> userMap = new HashMap<>();
        List<Long> userIds = new ArrayList<>();
        for (User user : userList) {
            userIds.add(user.getId());
            userMap.put(user.getId(), user);
        }

        // 5、员工表查询（员工用户id=用户id、职位（非空）、逻辑删除（未删除））
        Page<Employee> employeePage = this.page(page, Wrappers.lambdaQuery(Employee.class)
                .in(Employee::getUserId, userIds)
                .eq(position != null, Employee::getPosition, position)
                .eq(Employee::getDeleted, CommonDeleted.NOT_DELETED));

        // 6、封装VO数据列表
        List<EmployeeVO> employeeVOList = new ArrayList<>();
        for (Employee employee : employeePage.getRecords()) {
            User user = userMap.get(employee.getUserId());
            EmployeeVO employeeVO = getEmployeeVO(employee, user);
            employeeVOList.add(employeeVO);
        }

        // 7、将实体分页对象转换为VO分页对象
        Page<EmployeeVO> employeeVOPage = PageQueryUtils.convertToVOPage(employeePage, employeeVOList);

        // 8、返回封装结果
        return new PageResult<>(employeeVOPage.getTotal(), employeeVOPage.getPages(), employeeVOList);
    }

    /**
     * 根据id查询员工信息
     * @param id 员工id
     * @return 查询结果
     */
    @Override
    public EmployeeVO getEmployeeById(Long id) {
        // 1、检查员工是否存在
        Employee employee = checkEmployeeExist(id);

        // 2、根据用户id查询用户信息
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getId, employee.getUserId())
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));

        // 3、封装VO并返回
        return getEmployeeVO(employee, user);
    }

    /**
     * 修改员工信息
     * @param employeeUpdateDTO 修改的员工信息
     */
    @Override
    @Transactional
    public void updateEmployee(EmployeeUpdateDTO employeeUpdateDTO) {
        // 1、检查员工是否存在
        Long employeeId = employeeUpdateDTO.getId();
        Employee employee = checkEmployeeExist(employeeId);

        // 2、员工更新信息（移动电话、身份证号码、电子邮箱需要进行正则校验）
        // 移动电话
        String mobilePhone = employeeUpdateDTO.getMobilePhone();
        RegexUtils.checkMobilePhone(mobilePhone);
        // 身份证号码
        String idNumber = employeeUpdateDTO.getIdNumber();
        RegexUtils.checkIdNumber(idNumber);
        // 电子邮箱
        String email = employeeUpdateDTO.getEmail();
        RegexUtils.checkEmail(email);

        // 3、用户更新
        User user = new User();
        BeanUtils.copyProperties(employeeUpdateDTO, user);
        Long userId = employee.getUserId();
        user.setId(userId).setUpdateTime(LocalDateTime.now());
        userMapper.update(user, Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, userId));

        // 4、员工更新
        BeanUtils.copyProperties(employeeUpdateDTO, employee);
        employee.setUpdateTime(LocalDateTime.now());
        this.update(employee, Wrappers.lambdaUpdate(Employee.class)
                .eq(Employee::getId, employeeId));
    }

    /**
     * 删除员工（逻辑删除）
     * @param id 员工id
     */
    @Override
    @Transactional
    public void deleteEmployee(Long id) {
        // 1、检查员工是否存在
        Employee employee = checkEmployeeExist(id);

        // 2、删除员工（逻辑删除）
        this.update(new Employee(), Wrappers.lambdaUpdate(Employee.class)
                .eq(Employee::getId, id)
                .set(Employee::getDeleted, CommonDeleted.DELETED));

        // 3、删除用户（逻辑删除）
        userMapper.update(new User(), Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, employee.getUserId())
                .set(User::getDeleted, CommonDeleted.DELETED));
    }

    /**
     * 检查员工是否存在
     * @param employeeId 员工id
     * @return 员工对象
     */
    private Employee checkEmployeeExist(Long employeeId) {
        Employee employee = this.getOne(Wrappers.lambdaQuery(Employee.class)
                .eq(Employee::getId, employeeId)
                .eq(Employee::getDeleted, CommonDeleted.NOT_DELETED));
        if (employee == null) {
            // 员工账号不存在，抛出异常
            throw new AccountNotFoundException(MessageConstant.EMPLOYEE_ACCOUNT_NOT_FOUND);
        }
        return employee;
    }

    /**
     * 封装EmployeeVO
     * @param employee 员工信息
     * @param user 用户信息
     * @return EmployeeVO
     */
    private EmployeeVO getEmployeeVO(Employee employee, User user) {
        EmployeeVO employeeVO = new EmployeeVO();
        BeanUtils.copyProperties(employee, employeeVO);
        employeeVO.setUsername(user.getUsername())
                .setName(user.getName())
                .setGender(user.getGender())
                .setAge(user.getAge())
                .setMobilePhone(user.getMobilePhone())
                .setIdNumber(user.getIdNumber())
                .setEmail(user.getEmail())
                .setAddress(user.getAddress())
                .setAvatarUrl(user.getAvatarUrl())
                .setStatus(user.getStatus())
                .setLastLoginTime(user.getLastLoginTime());
        return employeeVO;
    }
}
